#include "qfitswindow.h"

//this is called a window, but it is essentially a widget that can also be embedded if it has a parent
QFitsWindow::QFitsWindow(QWidget *parent, Qt::WFlags fl )
		: QMainWindow(parent, fl) {
	fileName = QString::null;
	fits = 0;
	FITS::setVerboseMode(true);

	// FITSVIEW WIDGET
	sview = new ScrolledFitsView(this);
	setCentralWidget(sview);

	// MENU BAR
	// file menu
	QAction *openAction = new QAction(tr("&Open"), this);
		openAction->setShortcut(tr("Ctrl+O"));
		openAction->setStatusTip(tr("Open FITS file."));
		connect(openAction, SIGNAL(triggered()), this, SLOT(openFile()));
	QAction *exportAction = new QAction(tr("&Export PNG"), this);
		exportAction->setShortcut(tr("Ctrl+E"));
		exportAction->setStatusTip(tr("Export PNG file."));
		connect(exportAction, SIGNAL(triggered()), this, SLOT(exportFile()));
	QAction *quitAction = new QAction(tr("&Quit"), this);
		quitAction->setShortcut(tr("Ctrl+Q"));
		quitAction->setStatusTip(tr("Call it a day"));
		connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));
	QMenu *fileMenu = menuBar()->addMenu(tr("&File"));
		fileMenu->addAction(openAction);
		fileMenu->addSeparator(); 
		fileMenu->addAction(exportAction);
		fileMenu->addSeparator(); 
		fileMenu->addAction(quitAction);

	//view menu
	signalMapper = new QSignalMapper(this);// new signal mapper for new slot
	QAction *zoomFitAspectAction = new QAction(tr("Zoom Fit &Aspect"), this);
		zoomFitAspectAction->setStatusTip(tr("Zoom in to fit keeping the aspect ratio."));
		connect(zoomFitAspectAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoomFitAspectAction, -100); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(setZoomi(int)));
	signalMapper = new QSignalMapper(this);// new signal mapper for new slot
	//QAction *zoomFitAction = new QAction(tr("Zoom &Fit"), this);
		//zoomFitAction->setStatusTip(tr("Zoom in to fit."));
		//connect(zoomFitAction, SIGNAL(triggered()), view, SLOT(zoomFit()));
	QAction *zoomInAction = new QAction(tr("Zoom in (ctrl-m-up)"), this);
		zoomInAction->setStatusTip(tr("Zoom in 10%."));
		connect(zoomInAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoomInAction, 140); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(multZoomi(int)));
	QAction *zoomOutAction = new QAction(tr("Zoom out (ctrl-m-down)"), this);
		zoomOutAction->setStatusTip(tr("Zoom out 40%."));
		connect(zoomOutAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoomOutAction, 70); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(multZoomi(int)));
	signalMapper = new QSignalMapper(this);// new signal mapper for new slot
	QAction *zoom025Action = new QAction(tr("Zoom to 25%"), this);
		zoom025Action->setStatusTip(tr("Zoom to 25% of original size."));
		connect(zoom025Action, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoom025Action, 25); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(setZoomi(int)));
	QAction *zoom050Action = new QAction(tr("Zoom to 50%"), this);
		zoom050Action->setStatusTip(tr("Zoom to 50% of original size."));
		connect(zoom050Action, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoom050Action, 50); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(setZoomi(int)));
	QAction *zoom100Action = new QAction(tr("Zoom to 100%"), this);
		zoom100Action->setStatusTip(tr("Zoom to 100% of original size."));
		connect(zoom100Action, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoom100Action, 100); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(setZoomi(int)));
	QAction *zoom200Action = new QAction(tr("Zoom to 200%"), this);
		zoom200Action->setStatusTip(tr("Zoom to 200% of original size."));
		connect(zoom200Action, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoom200Action, 200); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(setZoomi(int)));
	QAction *zoom400Action = new QAction(tr("Zoom to 400%"), this);
		zoom400Action->setStatusTip(tr("Zoom to 400% of original size."));
		connect(zoom400Action, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(zoom400Action, 400); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(setZoomi(int)));
	QMenu *zoomMenu = new QMenu(tr("&Zoom"));
		zoomMenu->addAction(zoomFitAspectAction);
		//zoomMenu->addAction(zoomFitAction);
		zoomMenu->addSeparator();
		zoomMenu->addAction(zoomInAction);
		zoomMenu->addAction(zoomOutAction);
		zoomMenu->addSeparator();
		zoomMenu->addAction(zoom025Action);
		zoomMenu->addAction(zoom050Action);
		zoomMenu->addAction(zoom100Action);
		zoomMenu->addAction(zoom200Action);
		zoomMenu->addAction(zoom400Action);
	QMenu *colormapMenu = new QMenu(tr("&Colormap"));
	for(int i=0; i<13; i++){
		signalMapper = new QSignalMapper(this); // todo: 1 mapper should do, but fires 13 times
		QAction *colormapAction = new QAction(colormap.getName(i), this);
			colormapAction->setStatusTip(tr("Set colormap."));
			connect(colormapAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
			signalMapper->setMapping(colormapAction, i); // map to a signal with argument
			connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(setColormap(int))); // convert to different signal
		colormapMenu->addAction(colormapAction);
	}
	signalMapper = new QSignalMapper(this);// new signal mapper for new slot
	QAction *rotateLeftAction = new QAction(tr("Rotate left"), this);
		rotateLeftAction->setStatusTip(tr("Rotate left 90 degrees."));
		connect(rotateLeftAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(rotateLeftAction, -90); // map to a signal with argument
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(rotate(int)));
	QAction *rotateRightAction = new QAction(tr("Rotate right"), this);
		rotateRightAction->setStatusTip(tr("Rotate right 90 degrees."));
		connect(rotateRightAction, SIGNAL(triggered()), signalMapper, SLOT(map()));
		signalMapper->setMapping(rotateRightAction, 90);
		connect(signalMapper, SIGNAL(mapped(int)), sview, SLOT(rotate(int)));
	QMenu *rotateMenu = new QMenu(tr("&Rotate"));
		rotateMenu->addAction(rotateLeftAction);
		rotateMenu->addAction(rotateRightAction);
	QMenu *viewMenu = menuBar()->addMenu(tr("&View"));
		viewMenu->addMenu(zoomMenu);
		viewMenu->addMenu(colormapMenu);
		viewMenu->addMenu(rotateMenu);
	pluginMenu = menuBar()->addMenu(tr("&Plugins"));

	// application wide open gl settings
	QGLFormat f = QGLFormat::defaultFormat();
	f.setSampleBuffers(true);
	QGLFormat::setDefaultFormat(f);

	statusBar();

	// plugins:
	PluginManager *pluginManager = new PluginManager(this); // pass trough object for all the program's signals and slots
	pluginManager->loadPlugins(qApp->applicationDirPath());
	pluginManager->populateMenu(pluginMenu);
	// plugin signals and slots:
	connect( sview, SIGNAL(grayChanged(double, double)), pluginManager, SIGNAL(grayChanged(double, double)) );
	connect( pluginManager, SIGNAL(grayChanged(double, double)), sview, SLOT(setGray(double, double)) );
	// send two kind of signals if colormap changes
	connect( this, SIGNAL(colormapChanged(QVector<QColor>)),
			pluginManager, SIGNAL(colormapChanged(QVector<QColor>)) );
	connect( this, SIGNAL(colormapChanged(const unsigned*)),
			sview, SLOT(setColormap(const unsigned*)) );

}
QFitsWindow::~QFitsWindow(){
}

void QFitsWindow::print(QString s){
	qDebug(s.toAscii().data());
}

/**
 * SLOT
 */
void QFitsWindow::openFile(QString fileName){
	if(fileName.isEmpty()){ // e.g. if called from menu
		fileName = QFileDialog::getOpenFileName( 0 , QString::null, QString::null );
	}
	printf("opening: %s\n", fileName.toAscii().data());
	
	if(fileName.isEmpty())
		return;

	// delete old fits object
	if(fits!=0)
		delete fits;

	FITS *pInfile;
	try {
		pInfile = new FITS(fileName.toAscii().data(), Read, true);
	} catch (FitsException&) {
		// will catch all exceptions thrown by CCfits, including error
		// found by cfitsio (status != 0)
		std::cerr << " Fits Exception Thrown by test function \n";
		return;
	}
	fits = pInfile;

	sview->setFits(fits); // update the image
}

/**
 * SLOT, setcolormap
 */
void QFitsWindow::setColormap(int i){
	emit colormapChanged(colormap.getQVector(i));
	emit colormapChanged(colormap.getUInt(i));
}

/**
  * export PNG-file
  */
void QFitsWindow::exportFile(QString fileName){
}

